﻿using System;
using System.Collections.Generic;
using Library.OrmEnterpriseEntity.TableInfo;
using System.Text;

namespace Library.OrmEnterpriseEntity {
	/// <summary>
	/// Perform SQL Update statement
	/// </summary>
	public class UpdateQueryStatement : QueryStatement {
		internal UpdateQueryStatement(GlobalEntityView root)
			: this(root, null) {
		}
		internal UpdateQueryStatement(GlobalEntityView root, StringBuilder sqlTracking)
			: base(root) {
			NewCoumnValues = new List<KeyValuePair<DbColumnView, object>>();
			SqlTracking = sqlTracking;
		}
		/// <summary>
		/// Excute update statement
		/// </summary>
		/// <returns>Number of rows effected</returns>
		public override int Excute() {
			return Factor.DbContext.Instance.Context.ExcuteStatement(new UpdateStatementWrapper(this));
		}
		/// <summary>
		/// Set column by value
		/// </summary>
		/// <param name="column1">Specific column has to change value</param>
		/// <param name="value1">The new value for column</param>
		/// <exception cref="ArgumentNullException">throw when column or value is null</exception>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Set(DbColumnView column1, object value1) {
			if (column1 == null) throw new ArgumentNullException("column1");
			if (value1 == null) throw new ArgumentNullException("value1");
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column1, value1));
			return this;
		}
		/// <summary>
		/// Set columns by values
		/// </summary>
		/// <param name="column1">Specific column 1 has to change value</param>
		/// <param name="value1">The new value for column 1</param>
		/// <param name="column2">Specific column 2 has to change value</param>
		/// <param name="value2">The new value for column 2</param>
		/// <exception cref="ArgumentNullException">throw when column or value is null</exception>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Set(DbColumnView column1, object value1, DbColumnView column2, object value2) {
			if (column1 == null) throw new ArgumentNullException("column1");
			if (value1 == null) throw new ArgumentNullException("value1");

			if (column2 == null) throw new ArgumentNullException("column2");
			if (value2 == null) throw new ArgumentNullException("value2");
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column1, value1));
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column2, value2));
			return this;
		}
		/// <summary>
		/// Set columns by values
		/// </summary>
		/// <param name="column1">Specific column 1 has to change value</param>
		/// <param name="value1">The new value for column 1</param>
		/// <param name="column2">Specific column 2 has to change value</param>
		/// <param name="value2">The new value for column 2</param>
		/// <param name="column3">Specific column 3 has to change value</param>
		/// <param name="value3">The new value for column 3</param>
		/// <exception cref="ArgumentNullException">throw when column or value is null</exception>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Set(DbColumnView column1, object value1, DbColumnView column2, object value2, DbColumnView column3, object value3) {
			if (column1 == null) throw new ArgumentNullException("column1");
			if (value1 == null) throw new ArgumentNullException("value1");

			if (column2 == null) throw new ArgumentNullException("column2");
			if (value2 == null) throw new ArgumentNullException("value2");

			if (column3 == null) throw new ArgumentNullException("column3");
			if (value3 == null) throw new ArgumentNullException("value3");
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column1, value1));
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column2, value2));
			NewCoumnValues.Add(new KeyValuePair<DbColumnView, object>(column3, value3));
			return this;
		}
		/// <summary>
		/// Set columns by values
		/// </summary>
		/// <param name="keyValues">Column value pair</param>
		/// <exception cref="ArgumentNullException">throw when column or value is null</exception>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Set(params  KeyValuePair<DbColumnView, object>[] keyValues) {
			if (keyValues == null) return this;
			foreach (var keyValuePair in keyValues) {
				if (keyValuePair.Key == null) throw new ArgumentNullException("keyValues", @"Key is null");
				if (keyValuePair.Value == null) throw new ArgumentNullException("keyValues", @"Value is null");
				NewCoumnValues.Add(keyValuePair);
			}
			return this;
		}

		/// <summary>
		/// Join in update statement
		/// </summary>
		/// <param name="jointStatement">JoinStatement</param>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Join(JoinStatement jointStatement) {
			jointStatement.Statement = this;
			jointStatement.Root = Root;
			Joints.Add(jointStatement);
			return this;
		}
		/// <summary>
		/// Join in update statement
		/// </summary>
		/// <param name="table">joined table</param>
		/// <param name="joinExpr">join condition</param>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Join(GlobalEntityView table, QueryExpBuilder joinExpr) {
			return Join(new JoinStatement(table, joinExpr));
		}
		/// <summary>
		/// Join in update statement
		/// </summary>
		/// <param name="table">joined table</param>
		/// <param name="first">First column in join condition. The column must be belong to the table in update statment or the joined table</param>
		/// <param name="queryOperator">QueryOperator in join condition</param>
		/// <param name="second">Second column in join condition. The column must be belong to the joined table or the table in update statment</param>
		/// <returns></returns>
		public UpdateQueryStatement Join(GlobalEntityView table, DbColumnView first, QueryOperator queryOperator, DbColumnView second) {
			return Join(table, new QueryExpBuilder(first, queryOperator, second));
		}


		internal List<KeyValuePair<DbColumnView, object>> NewCoumnValues { get; private set; }
		/// <summary>
		/// Where clause in update statement
		/// </summary>
		/// <param name="whereExpression">Condition in where clause</param>
		/// <returns>UpdateQueryStatement</returns>
		public UpdateQueryStatement Where(QueryExpBuilder whereExpression) {
			if (whereExpression != null) {
				whereExpression.Statement = this;
				foreach (var expressionBuilder in whereExpression.Builders) {
					expressionBuilder.Statement = this;
				}
				WhereExpression = whereExpression;
			}
			return this;
		}
	}
}
